package org.springframework.aop.framework.autoproxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;

/**
 * @author: AirMan
 * @date: 2025/4/15 14:35
 * @description:
 */
public class MyA17 {

    static final Logger log = Logger.getLogger("myA17");

    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("aspect1", Aspect1.class);
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);

        context.refresh();

        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
//        creator.setProxyTargetClass(false);
        // 重要方法 findEligibleAdvisors =》 找到所有有资格的 Advisor
        List<Advisor> target1 = creator.findEligibleAdvisors(Target1.class, "target1");
        for (Advisor advisor : target1) {
            System.out.println(advisor);
        }
        // 重要方法 wrapIfnecessary =》 如果匹配成功就创建代理
        Object o1 = creator.wrapIfNecessary(new Target1(), "target1", "target1");
        Object o2 = creator.wrapIfNecessary(new Target2(), "target2", "target2");
        System.out.println(o1.getClass());
        System.out.println(o2.getClass());

        System.out.println("---------------------------------");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

    }


    static class Target1 implements I1{
        public void foo() {
            log.info("foo method...");
        }
    }

    static class Target2 {
        public void bar() {
            log.info("bar method...");
        }
    }

    interface I1{
        public void foo();
    }

    @Aspect
    static class Aspect1 {
        @Before("execution(* org.springframework.aop.framework.autoproxy..foo())")
        public void before() {
            log.info("aspect1 before...");
        }

        @After("execution(* org.springframework.aop.framework.autoproxy..foo())")
        public void after() {
            log.info("aspect1 after...");
        }
    }

    @Configuration
    static class Config {
        @Bean
        public Advisor advisor1(MethodInterceptor methodInterceptor) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut, methodInterceptor);
        }

        @Bean
        public MethodInterceptor methodInterceptor() {
            return new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
                    System.out.println("advisor before...");
                    Object result = invocation.proceed();
                    System.out.println("advisor after...");
                    return result;
                }
            };
        }
    }

}
